package de.tum.in.far.threedui.superbrickball.engine.physics.models;

import javax.media.j3d.Transform3D;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Quat4f;
import javax.vecmath.Tuple3f;
import javax.vecmath.Tuple4f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

public class PlaneModel extends PhysicalModel{

	// ax + by + cz =d
	private float a, b, c, d;
	Point3f arbitraryPoint;

	public PlaneModel(float a, float b, float c, float d) {
		this.a = a;
		this.b = b;
		this.c = c;
		this.d = d;
		makeArbitraryPoint();
	}

	public PlaneModel(Tuple4f abcd) {
		this.a = abcd.x;
		this.b = abcd.y;
		this.c = abcd.z;
		this.d = abcd.w;
		makeArbitraryPoint();
	}

	//tested
	public PlaneModel(Tuple3f normal, Tuple3f point) {
		this.a = normal.x;
		this.b = normal.y;
		this.c = normal.z;
		this.d = this.a * point.x + this.b * point.y + this.c * point.z;

		this.arbitraryPoint = new Point3f(point);
		
		System.out.printf("[%f, %f, %f, %f], [%s]\n", a, b ,c , d, point);
	}

	public PlaneModel(Transform3D transform) {
		Vector3f translation = new Vector3f();
		Quat4f rotation = new Quat4f();
		transform.get(translation);
		transform.get(rotation);

		Vector3f normal = new Vector3f(0, 0, 1);
		Transform3D rotationT3D = new Transform3D();
		rotationT3D.set(rotation);
		rotationT3D.transform(normal);
		
//		System.out.println("TRANSFORM :" + transform);
//		System.out.println("ROT T3D :" + rotationT3D);
//		System.out.println("NORMAL :" + normal);

		this.a = normal.x;
		this.b = normal.y;
		this.c = normal.z;
		this.d = this.a * translation.x + this.b * translation.y + this.c
				* translation.z;

		this.arbitraryPoint = new Point3f(translation);
	}

	public float distance(float x, float y, float z) {

//		double numerator = this.a * x + this.b * y + this.c * z - this.d;
//		double denemonator = Math.sqrt(this.a * this.a + this.b * this.b
//				+ this.c * this.c);
		
		double numerator = a * x + b * y + c * z - d;
		double denemonator = Math.sqrt(a*a + b * b + c * c);
		return (float) Math.abs(numerator / denemonator);
	}

	public float distance(Tuple3f point) {
		return distance(point.x, point.y, point.z);
	}

	public Vector3f getNormal() {
		return new Vector3f(this.a, this.b, this.c);
	}

	public void setNormal(float a, float b, float c) {
		this.a = a;
		this.b = b;
		this.c = c;
	}

	public void setNormal(Tuple3f normal) {
		setNormal(normal.x, normal.y, normal.z);
	}

	private void makeArbitraryPoint() {
		if (a != 0) {
			this.arbitraryPoint = new Point3f(d / a, 0, 0);
		} else if (b != 0) {
			this.arbitraryPoint = new Point3f(0, d / b, 0);
		} else {
			this.arbitraryPoint = new Point3f(0, 0, d / c);
		}
	}
	
	public float getZ(float x, float y)
	{
		return (d - this.a * x - this.b * y)/c;
	}
	
	public float getX(float y, float z)
	{
		return (d - this.b * y - this.c * z)/a;
	}
	
	public float getY(float x, float z)
	{
		return (d - this.a * x - this.c * z)/b;
	}
	
	
	public Transform3D getTransform()
	{
		Transform3D transform = new Transform3D();
		transform.setIdentity();
		Point3d standingAt = new Point3d(this.arbitraryPoint);
		Point3d lookingAt = new Point3d(this.arbitraryPoint);//new Point3d(0,0,-.5f);
		lookingAt.add(new Point3d(this.getNormal()));
		
		
		
		transform.lookAt(standingAt, lookingAt, new Vector3d(1,1,1));
		
		transform.invert();
		
		return transform;
		
		
	}
}
